<template>
  <div class="mind-map-list">
    <div id="container"></div>

    <!-- 故障描述弹框 -->
    <faultDescription 
      v-model="faultDescriptionDialogVisible" 
      :create-fault-data="createFaultData"
      @operateSuc="operateSuc"
    />

    <!-- 解决方案弹框 -->
    <FaultSolution 
      v-model="faultSolutionDialogVisible" 
      :create-fault-data="createFaultData"
      @operateSuc="operateSuc"
    />
  </div>
</template>
  
<script>
import { defaultEdge, layout, colorArr } from '../mode/initData';
import G6 from '@antv/g6';
// console.log(G6.Util, 'UTIL')
// predictLayout 表示预测的布局，如 force 或 radial
// confidence 表示预测的可信度
import { openAccurateTab } from '@src/util/platform';

import { PageRoutesTypeEnum } from 'pub-bbx-global/pageType/dist/enum/PageRoutesEnum';
// api
import { libraryDelete, solutionDelete } from '@src/api/Fault';
import AuthUtil from '@src/util/auth';

// 故障描述弹框
import FaultDescription from '@src/modules/faultLibrary/components/FaultInformationDialog/FaultDescription';
// 解决方案弹框
import FaultSolution from '@src/modules/faultLibrary/components/FaultInformationDialog/FaultSolution';

const fontSizes = [16, 14, 12]
import { cloneDeep } from 'lodash';

export default{
  // 故障库思维导图
  name:'MindMapList',
  
  props: {
    faultList:{
      type:Array,
      default: () => ([])
    },
    // 画布大小
    canvasSize: {
      type: String,
      default: '100%'
    },
    initData: {
      type: Object,
      default: () => ({})
    },
  },
  
  data() {
    return {
      graph:null,
      // 新建/编辑故障描述弹框
      faultDescriptionDialogVisible: false,
      // 用于记录新建故障描述和解决方案时一些数据，从列表取得，传给弹框
      createFaultData:{},
      // 新建/编辑解决方案弹框
      faultSolutionDialogVisible:false,

    }
  },

  mounted() {
    this.initTree()
  },
  computed: {
    auth() {
      return this.initData?.auths || {};
    },
    hasFaultAdd() {
      return AuthUtil.hasAuth(this.auth, 'FAULT_LIBRARY_ADD')
    },
    hasFaultEdit() {
      return AuthUtil.hasAuth(this.auth, 'FAULT_LIBRARY_EDIT')
    },
    hasFaultDelete() {
      return AuthUtil.hasAuth(this.auth, 'FAULT_LIBRARY_DELETE')
    }
  },
  methods:{
    initTree(){
      // 自定义根节点
      G6.registerNode('dice-mind-map-root', {
        jsx: this.registerDiceMindMapRoot,
        getAnchorPoints() {
          return [
            [0, 0.5],
            [1, 0.5],
          ];
        },
      }, 'single-node');

      // 自定义二级节点
      G6.registerNode('dice-mind-map-sub', {
        // jsx: this.registerDiceMindMapSub,
        draw: (cfg, group) => this.draw(cfg, group, 1),
        getAnchorPoints() {
          return [
            [0, 0.965],
            [1, 0.965],
          ];
        },
      }, 'single-node');

      // 自定义除根节点和二级节点以外的节点
      G6.registerNode('dice-mind-map-leaf', {
        draw: (cfg, group) => this.draw(cfg, group, 2),
        // jsx: this.registerDiceMindMapLeaf,
        getAnchorPoints() {
          return [
            [0, 0.965],
            [1, 0.965],
          ];
        },
      }, 'single-node');

      G6.registerBehavior('dice-mindmap', {
        getEvents() {
          return {
            // 'node:click': 'clickNode'
          };
        },
        // clickNode: this.clickNode
      });

      // 获取宽度
      this.graph = new G6.TreeGraph(this.initParams());
      
      this.reRender()
    },
    draw(cfg, group, type) {
      const fontSize = fontSizes[type]
      const { label, width, height } = cfg
      // const {text, lineCount} = this.superLongTextHandle(cfg.label, fontSize)
      // console.log(text, lineCount, 123412342)
      const color = cfg.color || cfg.style.stroke;
      // let width = G6.Util.getTextSize(text, fontSize)[0];
      // width = this.getMaxWidth(width, fontSize)
      // width = this.getMaxWidth(width, fontSize)
      // const height = lineCount * 22
      const newWidth = width + 46;
      const halfWidth = Math.ceil(newWidth / 2)
      // 绘制节点
      const keyShape = group.addShape('rect', {
        attrs: {
          x: -halfWidth,
          y: -height,
          width: newWidth,
          height,
          fill: 'transparent',
          // stroke: '#000',
        },
        cursor: 'pointer',
        name: 'rect-shape',
      });
      // 绘制文本
      let textBtn = group.addShape('text', {
        attrs: {
          x: -halfWidth,
          y: -height,
          text: label,
          // textAlign: 'center',
          textBaseline: 'top',
          fill: '#000',
          fontSize,
          lineHeight: 18,
          cursor: 'pointer',
        },
        name: 'rect-text',
      });
      // 绘制+
      let addBtn = group.addShape('text', {
        attrs: {
          x: halfWidth - 44,
          y: -height,
          text: '+',
          textBaseline: 'top',
          fill: '#262626',
          fontSize: 16,
          lineHeight: 18,
          cursor: 'pointer',
        },
        visible: false,
        name: 'rect-tex2',
      });

      let solutionBtn = group.addShape('text', {
        attrs: {
          x: halfWidth - 30,
          y: -height,
          fontFamily: 'iconfont', // 对应css里面的font-family: "iconfont";
          textBaseline: 'top',
          fill: '#262626',
          fontSize: 16,
          lineHeight: 18,
          cursor: 'pointer',
          text: '\ue807',
        },
        visible: false,
        name: 'rect-tex4',
      });

      // 绘制-
      let deleteBtn = group.addShape('text', {
        attrs: {
          x: halfWidth - 10,
          y: -height,
          text: '-',
          textBaseline: 'top',
          fill: '#262626',
          fontSize: 16,
          lineHeight: 18,
          cursor: 'pointer',
        },
        visible: false,
        name: 'rect-tex3',
      });

      // 绘制横线
      group.addShape('line', {
        attrs: {
          x1: -halfWidth,
          y1: 0,
          x2: halfWidth,
          y2: 0,
          stroke: color,
          lineWidth: 2,
        },
        cursor: 'pointer',
        name: 'rect-line',
      });

      group.on('mouseenter', () => {
        // 新建
        if(!cfg.libraryId && this.hasFaultAdd) {
          if (!cfg.solutionList || cfg.solutionList.length === 0) {
            addBtn.show()
          }
          if (cfg.faultLevel != 1 && !(cfg.children || []).find(v => v.dataType === 1)) {
            solutionBtn.show()
          }
        }

        if (this.hasFaultDelete) {
          deleteBtn.show()
        }
      })
      
      group.on('mouseleave', () => {
        addBtn.hide()
        deleteBtn.hide()
        solutionBtn.hide()
      })

      addBtn.on('click', () => {
        this.createDescriptionOrSolution(cfg, 'description')
      })
      deleteBtn.on('click', () => {
        this.handleClickDelete(cfg)
      })
      textBtn.on('click', () => {
        this.openDetail(cfg)
      })
      solutionBtn.on('click', () => {
        this.createDescriptionOrSolution(cfg, 'solution')
      })
      return keyShape;
    },
    setCreateData(parentData = {}){
      const { faultLevel } = parentData
      this.createFaultData = {
        parentId: parentData.id,
        faultLevel: faultLevel + 1,
        parentDesc: parentData.label
      }
    },
    
    // 新建描述或解决方案
    createDescriptionOrSolution(parentData, type){

      // 新建描述或子描述需要传递当前新建的级别和父节点id给弹框组件，用于提交给接口
      this.setCreateData(parentData, type)

      switch(type){
        case 'description': this.openDescription(); break;
        case 'solution': this.openSolution(); break;
        default: break;
      }
      
    },

    // 打开描述和子描述弹框
    openDescription(id = ''){
      this.faultDescriptionDialogVisible = true;
    },

    // 打开解决方案弹框
    openSolution(id = ''){
      this.faultSolutionDialogVisible = true
    },
    // 删除
    handleClickDelete(val) {
      const { libraryId, id } = val || {};
      this.$confirm(this.$t('common.paas.view.designer.workFlow.tip1'), this.$t('common.base.toast'), {
        confirmButtonText: this.$t('common.base.makeSure'),
        cancelButtonText: this.$t('common.base.cancel'),
        type: 'warning'
      }).then(async () => {
        let res = {}
        if(libraryId){
          // 当前是解决方案
          res = await solutionDelete({solutionId:id})
        }else{
          // 删除故障对象
          res = await libraryDelete({faultId:id})
        }

        if(res.status === 0){
          this.operateSuc();
        }else{
          this.$notify.error({
            title: this.$t('common.base.toast'),
            message: res.message,
            duration: 2000,
          });
        }
      })
    },
    operateSuc(){
      this.$emit('getData')
    },
    // 递归处理 精简数据
    findNode(list){
      return list.map(x => {
        let children = [];

        if(x.childrenList?.length) {
          children = this.findNode(x.childrenList)
        }

        return {
          id: x.id,
          label: x.faultDesc,
          children,
          faultLevel: x.faultLevel,
          dataType: x.dataType,
          libraryId: x.libraryId,
          solutionList: x.solutionList
        }
      })
    },

    getData(data){
      const cloneDeepFaultList = cloneDeep(data?.length ? [ ...data ] : [ ...this.faultList ]);
      const faultTree = this.findNode(cloneDeepFaultList);
      
      let treeData = {
        id: '0001',
        label: this.$t('faultLibrary.title'),
        children: faultTree
      }
      // 处理接口来的数据字段结构转成G6需要的格式
      // G6.Util.traverseTree(treeData, (subTree) => {
      //   const { id, label, children, faultDesc, childrenList } = subTree
      //   !label && (subTree.label = faultDesc);
      //   !children && (subTree.children = childrenList)
      // });

      return treeData
    },

    reRender(data = []){
      this.graph.data(this.dataTransform(this.getData(data)));
      this.graph.clear();
      this.graph.render();
      this.graph.focusItem('0001')
      this.graph.on('wheelzoom', e => {
        const zoom = this.graph.getZoom();
        this.$emit('zoomChange', zoom)
      })
    },

    // 初始化参数
    initParams(){
      const container = document.getElementById('container');
      return {
        container: 'container',
        width: container.scrollWidth,
        height: container.scrollHeight,
        // 像素比
        // pixelRatio: 2,
        // 是否开启画布自适应。开启后图自动适配画布大小。
        // fitView: true,
        // fitCenter: true,
        // fitView 为 true 时生效。图适应画布时，指定四周的留白。
        // fitViewPadding: [100, 100],
        // 模式
        minZoom: 0.25,
        zoom: 1,
        modes: {
          default: ['dice-mindmap', 'drag-canvas', 'zoom-canvas', 'scroll-canvas', 'activate-relations', 'collapse-expand-combo']
        },
        // 连线类型及样式
        defaultEdge,
        // 布局
        layout,
      }
    },
    superLongTextHandle(str, fontSize) {
      const maxWidth = 166;
      let currentWidth = 0;
      let res = str; // 区分汉字和字母
      let lineCount = 1; // 记录总行数
      // const pattern = /[\u4E00-\u9FA5]+/;
      str.split('').forEach((letter, i) => {
        if (currentWidth > maxWidth) return;
        // currentWidth += pattern.test(letter) ? 2 : 1;
        // if (pattern.test(letter)) { // 中文字符
        //   currentWidth += G6.Util.getLetterWidth(letter, fontSize);
        // } else {// 根据字体大小获取单个字母的宽度
        // }
        currentWidth += G6.Util.getLetterWidth(letter, fontSize);
        // console.log(result, 'result')
        if (currentWidth > maxWidth) {
          const result = this.superLongTextHandle(str.substr(i), fontSize);
          res = `${str.substr(0, i)}\n${result.text}`;
          lineCount += result.lineCount; // 累加总行数
        }
      });
      return { text: res, lineCount };
    },
    getMaxWidth(width) {
      return Math.min(width, 210)
      // return Math.min(15 * fontSize, 210)
    },

    // 自定义根节点
    registerDiceMindMapRoot(cfg){
      const width = G6.Util.getTextSize(cfg.label, fontSizes[0])[0] + 24;
      const stroke = '#5B8FF9';

      return `
      <group>
        <rect draggable="true" style={{width: ${width}, height: 42, stroke: ${stroke}, radius: 4, cursor: pointer }} keyshape>
          <text style={{ fontSize: ${fontSizes[0]}, marginLeft: 12, marginTop: 12 }}>${cfg.label}</text>
        </rect>
      </group>
    `;
    },

    // 自定义二级节点
    // registerDiceMindMapSub(cfg){
    //   const width = G6.Util.getTextSize(cfg.label, fontSizes[1])[0] + 24;
    //   const color = cfg.color || cfg.style.stroke;

    //   return `
    //   <group>
    //     <rect draggable="true" style={{width: ${this.getMaxWidth(width + 24)}, height: 22}} keyshape>
    //       <text draggable="true" style={{ fontSize: ${fontSizes[1]}, marginLeft: 12, marginTop: 6 }}>${ this.insetEnter(cfg.label, fontSizes[1]) }</text>
    //     </rect>
    //     <rect style={{ fill: ${color}, width: ${this.getMaxWidth(width + 24)}, height: 2, x: 0, y: 22 }} />
    //   </group>
    // `;
    // },

    // 自定义除根节点和二级节点以外的节点
    // registerDiceMindMapLeaf(cfg){
    //   const width = G6.Util.getTextSize(cfg.label, fontSizes[2])[0] + 24;
    //   const color = cfg.color || cfg.style.stroke;

    //   return `
    //   <group>
    //     <rect draggable="true" style={{width: ${this.getMaxWidth(width + 20)}, height: 26, fill: 'transparent' }}>
    //       <text style={{ fontSize: ${fontSizes[2]}, marginLeft: 12, marginTop: 6 }}>${this.insetEnter(cfg.label, fontSizes[2])}</text>
    //     </rect>
    //     <rect style={{ fill: ${color}, width: ${this.getMaxWidth(width + 24)}, height: 2, x: 0, y: 32 }} />
    //   </group>
    //   `;
    // },

    dataTransform (data) {
      const changeData = (d, level = 0, color) => {
        const data = { ...d };
        switch (level) {
          case 0:
            data.type = 'dice-mind-map-root';
            break;
          case 1:
            data.type = 'dice-mind-map-sub';
            break;
          default:
            data.type = 'dice-mind-map-leaf';
            break;
        }

        // data.faultLevel === 1 && (data.color = colorArr[Math.floor(Math.random() * colorArr.length)])
        let fontSize
        if (data.faultLevel === 1) {
          data.color = colorArr[Math.floor(Math.random() * colorArr.length)]
          fontSize = fontSizes[0]
        } else if(data.faultLevel === 2) {
          fontSize = fontSizes[1]
        } else {
          fontSize = fontSizes[2]
        }
        let width = G6.Util.getTextSize(data.label, fontSize)[0];
        width = this.getMaxWidth(width, fontSize)
        const {text, lineCount} = this.superLongTextHandle(data.label, fontSize)

        // 先直接替换掉原文，后续有其他需要再改~
        data.label = text
        data.width = width
        data.height = lineCount * 18
        // data.fontSize = height
        color && (data.color = color);

        if (d.children) {
          data.children = d.children.map((child) => changeData(child, level + 1, data.color));
        }
        return data;
      };
      return changeData(data);
    },

    graphZoom(value, center){
      // const { offsetHeight, offsetWidth} = document.getElementById('container')
      const centerX = Math.round(this.graph.get('width') / 2);
      const centerY = Math.round(this.graph.get('height') / 2);
      // const zoom = this.graph.getZoom();
      // console.log(value, zoom, 'value')
      if(value === '') {
        this.graph.fitView()
        // this.graph.focusItem('0001', false)
      } else {
        this.graph.zoomTo(value, center || { x: centerX, y: centerY})
      }
    },

    // 点击事件
    clickNode(evt){

      const model = evt.item.get('model');
      // const name = evt.target.get('action');
      // 打开详情页面
      // this.openDetail(model)
      
    },
    openDetail(data){
      const { faultLevel, id, libraryId } = data || {}

      let type = 'description'
      if(faultLevel === 1){
        type = 'obj'
      }else if(libraryId){
        type = 'solution'
      }
      let fromId = window.frameElement.getAttribute('id');
      openAccurateTab({
        type: PageRoutesTypeEnum.PageFaultLibraryDetail,
        key: id,
        params:`type=${type}`,
        fromId
      })
    }
  },
  components:{
    FaultDescription,
    FaultSolution
  },
}
</script>

<style lang="scss" scoped>
.mind-map-list {
  margin: 0px auto;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  flex: 1;
  overflow: hidden;
}
#container {
  width: 100%;
  height: 100%;
  overflow: auto;
}
#container::-webkit-scrollbar {
  display: none;
}
</style>